﻿using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Services;
using System.Threading;
using System.Threading.Tasks;
using Wfxin.RabbitMQ;

namespace Wfxin.Web.Api.MQ
{
 
    public class RabbitMQOrderConsumer: IProcessingServer
    {
        protected readonly ILogger _Logger = null;
        private readonly CancellationTokenSource _cts;
        private readonly TimeSpan _pollingDelay = TimeSpan.FromSeconds(1);
        private readonly IOrderConsumerClientFactory _ConsumerClientFactory = null;
  
        
        //private readonly IFreeSeqCodePublishMessageSender m_Sender = null;
        //private readonly IZDaDistributedRedisCache m_SECache = null;
        public RabbitMQItem RabbitMQItem { get; private set; }
         
        /// <summary>
        /// 
        /// </summary>
        public void Start()
        {
            using (var client = _ConsumerClientFactory.Create(RabbitMQItem.QueueName))
            {
                RegisterMessageProcessor(client);

                client.Subscribe(new[] { RabbitMQItem.RouteKey, $"{RabbitMQItem.RouteKey}_v2", $"{RabbitMQItem.RouteKey}_v3" });

                client.Listening(_pollingDelay, _cts.Token);
            } 
        }


        private void RegisterMessageProcessor(IConsumerClient client)
        {
            client.OnMessageReceived += (sender, messageContext) =>
            {
                try
                {
                    //var item = JsonConvert.DeserializeObject<MQDataWrapper<OrderEntity>>(messageContext.Content);

                    //long orderId = 0L;
                    //int code = 0;
                    //string msg = string.Empty;
                    //if (messageContext.Name.EndsWith("_v2"))
                    //{
                    //    this.m_OrderDao.CreateOrder(item.Data, out orderId, out code, out msg);
                    //}
                    //else if (messageContext.Name.EndsWith("_v3"))
                    //{
                    //    this.m_OrderDao.CreateOrderV2(item.Data, out orderId, out code, out msg);
                    //}
                    //else
                    //{
                    //    this.m_OrderDao.CreateOrder(item.Data, out code, out msg);
                    //}

                    //if (code == 0)
                    //{
                    //    this.m_SysLoggingStorage.Write(LogLevel.Information, item.UserName, null, item.Req_Scheme, item.Req_Host, item.Req_ContentLength,
                    //        item.Req_ContentType, item.Req_Method, item.Req_Path, $"[{code}]{msg}。返回订单编号：{orderId}，数据：{messageContext.Content}");
                    //}
                    //else
                    //{
                    //    this.m_SysLoggingStorage.Write(LogLevel.Warning, item.UserName, null, item.Req_Scheme, item.Req_Host, item.Req_ContentLength,
                    //        item.Req_ContentType, item.Req_Method, item.Req_Path, $"[{code}]{msg}，数据：{messageContext.Content}");
                    //}

                    client.Commit();

                    //if (code == 0 && !string.IsNullOrEmpty(item.Data.SeqNum))
                    //{
                    //    try
                    //    {
                    //        this.m_SECache.KeyDeleteStartWith("Cache_Online_");
                    //    }
                    //    catch (Exception ex)
                    //    {
                    //        this.m_Logger.LogError(ex, "清除线上订单缓存发生异常");
                    //    }
                    //    try
                    //    {
                    //        //发送消息助手消息
                    //        var order = this.m_OnlineOrderDao.FindBySeqNum(item.Data.SeqNum);
                    //        if (order != null)
                    //        {
                    //            this.m_OnlineOrderDao.SaveSRNotice(order.UserId, order.Id, "4");
                    //        }
                    //    }
                    //    catch (Exception ex)
                    //    {
                    //        this.m_Logger.LogError(ex, "根据订单流水号获取线上订单信息发生异常");
                    //    }

                    //    MQDataWrapper<string> w = new MQDataWrapper<string>(item.UserName,
                    //        item.Req_Scheme, item.Req_Host, item.Req_ContentLength, item.Req_ContentType, item.Req_Method, item.Req_Path);
                    //    w.Data = item.Data.SeqNum;

                    //    //处理订单流水号，加入延时队列，到时间自动释放
                    //    this.m_Sender.SendAsync(w);
                    //}
                }
                catch (Exception ex)
                {
                    //this.m_Logger.LogError(ex, "处理数据发生异常，数据：'{0}'。", messageContext);

                    ////client.Reject();
                    //try
                    //{
                    //    client.MoveToReply(Encoding.UTF8.GetBytes(messageContext.Content));
                    //}
                    //catch (Exception ex2)
                    //{
                    //    m_Logger.LogError(ex2, "重试数据发生异常，数据：'{0}'。", messageContext);
                    //}
                }
            };

            client.OnLog += WriteLog;
        }

        private void WriteLog(object sender, LogMessageEventArgs logmsg)
        {
            switch (logmsg.LogType)
            {
                case MqLogType.ConsumerCancelled:
                    _Logger.LogWarning("RabbitMQ 消费者取消。--> " + logmsg.Reason);
                    break;
                case MqLogType.ConsumerRegistered:
                    this._Logger.LogInformation("RabbitMQ 消费者注册。--> " + logmsg.Reason);
                    break;
                case MqLogType.ConsumerUnregistered:
                    this._Logger.LogWarning("RabbitMQ 消费者注销。--> " + logmsg.Reason);
                    break;
                case MqLogType.ConsumerShutdown:
                    this._Logger.LogWarning("RabbitMQ 消费者断线。 --> " + logmsg.Reason);
                    Reconnect();
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }


        private void Reconnect()
        {
            var mres = new ManualResetEventSlim(false); // state is initially false

            while (!mres.Wait(1000 * 5)) // loop until state is true, checking every 5s
            {
                try
                {
                    Start();

                    _Logger.LogInformation("RabbitMQ 重连成功。");
                    mres.Set(); // state set to true - breaks out of loop
                }
                catch (Exception ex)
                {
                    _Logger.LogWarning("RabbitMQ 重连失败。");
                }
            }
        }
    }
}
